#include "drv_adc.h"
#include "delay.h"
#include <stdio.h>

void drv_adc_sleep_enter(void){
	ADC_StopConvert(M4_ADC1);
	ADC_DeInit(M4_ADC1);
	PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Disable);
//	PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Disable);
	//CLK_UpllCmd(Disable);
}

void drv_adc_sleep_exit(void){
	ADC1_init();
	PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
	PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable);
}

/**
 *******************************************************************************
 ** \brief  Set an ADC pin as analog input mode or digit mode.
 **
 ******************************************************************************/
static void AdcSetPinMode(uint8_t u8AdcPin, en_pin_mode_t enMode){
	en_port_t enPort = PortA;
	en_pin_t enPin   = Pin00;
	bool bFlag       = true;
	stc_port_init_t stcPortInit;

	MEM_ZERO_STRUCT(stcPortInit);
	stcPortInit.enPinMode = enMode;
	stcPortInit.enPullUp  = Disable;

	switch (u8AdcPin){
		case ADC1_IN0:
			enPort = PortA;
			enPin  = Pin00;
		break;

		case ADC1_IN1:
			enPort = PortA;
			enPin  = Pin01;
		break;

		case ADC1_IN2:
			enPort = PortA;
			enPin  = Pin02;
		break;

		case ADC1_IN3:
			enPort = PortA;
			enPin  = Pin03;
		break;

		case ADC12_IN4:
			enPort = PortA;
			enPin  = Pin04;
		break;

		case ADC12_IN5:
			enPort = PortA;
			enPin  = Pin05;
		break;

		case ADC12_IN6:
			enPort = PortA;
			enPin  = Pin06;
		break;

		case ADC12_IN7:
			enPort = PortA;
			enPin  = Pin07;
		break;

		case ADC12_IN8:
			enPort = PortB;
			enPin  = Pin00;
		break;

		case ADC12_IN9:
			enPort = PortB;
			enPin  = Pin01;
		break;

		case ADC12_IN10:
			enPort = PortC;
			enPin  = Pin00;
		break;

		case ADC12_IN11:
			enPort = PortC;
			enPin  = Pin01;
		break;

		case ADC1_IN12:
			enPort = PortC;
			enPin  = Pin02;
		break;

		case ADC1_IN13:
			enPort = PortC;
			enPin  = Pin03;
		break;

		case ADC1_IN14:
			enPort = PortC;
			enPin  = Pin04;
		break;

		case ADC1_IN15:
			enPort = PortC;
			enPin  = Pin05;
		break;

		default:
			bFlag = false;
		break;
	}

	if (true == bFlag){
		PORT_Init(enPort, enPin, &stcPortInit);
	}
}

/**
 *******************************************************************************
 ** \brief  Config the pin which is mapping the channel to analog or digit mode.
 **
 ******************************************************************************/
static void AdcSetChannelPinMode(const M4_ADC_TypeDef *ADCx,uint32_t u32Channel,en_pin_mode_t enMode){
	uint8_t u8ChIndex;
#if (ADC_CH_REMAP)
	uint8_t u8AdcPin;
#else
	uint8_t u8ChOffset = 0u;
#endif

	if (M4_ADC1 == ADCx){
		u32Channel &= ADC1_PIN_MASK_ALL;
	}
	else{
		u32Channel &= ADC2_PIN_MASK_ALL;
#if (!ADC_CH_REMAP)
		u8ChOffset = 4u;
#endif
	}

	u8ChIndex = 0u;
	while (0u != u32Channel){
		if (u32Channel & 0x1ul){
#if (ADC_CH_REMAP)
		u8AdcPin = ADC_GetChannelPinNum(ADCx, u8ChIndex);
		AdcSetPinMode(u8AdcPin, enMode);
#else
		AdcSetPinMode((u8ChIndex+u8ChOffset), enMode);
#endif
		}

		u32Channel >>= 1u;
		u8ChIndex++;
	}
}


/**
 *******************************************************************************
 ** \brief  ADC clock configuration.
 **
 ** \note   1) ADCLK max frequency is 60MHz.
 **         2) If PCLK2 and PCLK4 are selected as the ADC clock,
 **            the following conditions must be met:
 **            a. ADCLK(PCLK2) max 60MHz;
 **            b. PCLK4 : ADCLK = 1:1, 2:1, 4:1, 8:1, 1:2, 1:4
 **
 ******************************************************************************/
static void AdcClockConfig(void){	
//    stc_clk_xtal_cfg_t stcXtalCfg;
    stc_clk_upll_cfg_t stcUpllCfg;

//    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcUpllCfg);

//    /* Use XTAL as UPLL source. */
//    stcXtalCfg.enFastStartup = Enable;
//    stcXtalCfg.enMode = ClkXtalModeOsc;
//    stcXtalCfg.enDrv = ClkXtalLowDrv;
//    CLK_XtalConfig(&stcXtalCfg);
//    CLK_XtalCmd(Enable);
	CLK_HrcCmd(Enable);//使能HRC时钟

    /* Set UPLL out 240MHz. */
    stcUpllCfg.pllmDiv = 2u;
    /* upll = 8M(XTAL) / pllmDiv * plln */
    stcUpllCfg.plln    = 30u;
    stcUpllCfg.PllpDiv = 16u;
    stcUpllCfg.PllqDiv = 16u;
    stcUpllCfg.PllrDiv = 16u;
    CLK_SetPllSource(ClkPllSrcHRC);
    CLK_UpllConfig(&stcUpllCfg);
    CLK_UpllCmd(Enable);
    CLK_SetPeriClkSource(ClkPeriSrcUpllr);

}
/**
 *******************************************************************************
 ** \brief  ADC1 initial configuration.
 **
 ******************************************************************************/
static void AdcInitConfig(void){
	stc_adc_init_t stcAdcInit;

	MEM_ZERO_STRUCT(stcAdcInit);

	stcAdcInit.enResolution = AdcResolution_12Bit;
	stcAdcInit.enDataAlign  = AdcDataAlign_Right;
	stcAdcInit.enAutoClear  = AdcClren_Disable;
	stcAdcInit.enScanMode   = ADC1_SCAN_MODE;
	/* 1. Enable ADC1. */
	PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable);
	/* 2. Initialize ADC1. */
	ADC_Init(M4_ADC1, &stcAdcInit);
}

/**
 *******************************************************************************
 ** \brief  ADC channel configuration.
 **
 ******************************************************************************/
static void AdcChannelConfig(void){
	stc_adc_ch_cfg_t stcChCfg;
	stc_adc_awd_cfg_t stcAwdCfg;

	uint8_t au8Adc1SaSampTime[ADC1_SA_CHANNEL_COUNT] = ADC1_SA_CHANNEL_SAMPLE_TIME;
	MEM_ZERO_STRUCT(stcChCfg);
	MEM_ZERO_STRUCT(stcAwdCfg);
	/* 1. Set the ADC pin to analog mode. */
	AdcSetChannelPinMode(M4_ADC1, ADC1_CHANNEL, Pin_Mode_Ana);
	stcChCfg.u32Channel  = ADC1_CHANNEL;
	stcChCfg.u8Sequence  = ADC_SEQ_A;
	stcChCfg.pu8SampTime = au8Adc1SaSampTime;
	/* 2. Add ADC channel. */
	ADC_AddAdcChannel(M4_ADC1, &stcChCfg);
}

static void AdcTriggerConfig(void){
	PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
	/* ADC1 sequence A will be started by software. */
	ADC_TriggerSrcCmd(M4_ADC1, ADC_SEQ_A, Disable);
}

//ADC初始化
void ADC1_init(void){
	AdcClockConfig();
	AdcInitConfig();
	AdcChannelConfig();
	AdcTriggerConfig();
	//------------------------------------------------------------------//
	/* Start ADC1. */
	ADC_StartConvert(M4_ADC1);
	/* ADC1 sequence A. Waiting for sequence A conversion end. */
	while (Reset == ADC_GetEocFlag(M4_ADC1, ADC_SEQ_A)){;}
	/* Clear EOC(End of Conversion) flag. */
	ADC_ClrEocFlag(M4_ADC1, ADC_SEQ_A);	 
}


static void adcValueSort(uint16_t *valueArray,uint8_t arraySize){
	uint8_t i = 0;
	uint8_t t = 0;
	for(t = 0; t < arraySize; t++){
		for(i=0;i<arraySize - 1 - t;i++){
			if(valueArray[i] > valueArray[i+1]){
				valueArray[i+1] = valueArray[i+1] + valueArray[i];
				valueArray[i] = valueArray[i+1] - valueArray[i];
				valueArray[i+1] = valueArray[i+1] - valueArray[i];
			}
		}
	}
}


uint16_t ADC_read_register_value(uint8_t ch){
	uint16_t m_au16Adc1Value = 0;
	M4_ADC1->STR = (uint8_t)0x01;
		ADC_GetChData(M4_ADC1, 1<<ch,&m_au16Adc1Value, 1);
		M4_ADC1->ISR_f.EOCAF = 0u;
		
	return m_au16Adc1Value;
}

float get_adc_vol_value(uint8_t ch){
	uint16_t adcArray[200] = {0};
	float averageAdc = 0.0;
	memset((char *)adcArray,0,sizeof(adcArray));
	uint8_t i = 0;
	for(i=0;i<200;i++){
		adcArray[i] = ADC_read_register_value(ch);
	}
	adcValueSort(adcArray,200);
	
	for(i=100;i<200;i++){
		averageAdc += (float)adcArray[i];
	}
	averageAdc/=100.0;
//	printf("averageAdc = %04f\n",averageAdc);
	return 3300.0*averageAdc/4096.0;
}



